iT邦幫忙

2026 iThome 鐵人賽

DAY 20
0
Claude AI

資深工程師的 Claude Code 工作筆記系列 第 20 篇

Day 20:MCP 最近的大改版,以及怎麼接、怎麼收權限、怎麼用好

  • 分享至 

  • xImage
  •  

Day 17 到 19 一路在講「誰能做什麼」:hooks 在事件層把規則寫死,subagent 在角色層用 tools 收邊界,skill 用一段描述讓模型決定要不要載入指引。今天講工具從哪裡來。答案幾乎都是 MCP,而它最近的變動不小,連協定本身都換了一個大版本

規格最新版是 2026-07-28

規格版本頁現在標示的最新版是 2026-07-28,不是 2025-11-25,而且是一次大改版。四個版本的重點如下,皆取自各版 changelog 的 Key Changes:

版本 重點
2025-03-26 OAuth 2.1 授權框架、Streamable HTTP 取代 HTTP+SSE、tool annotations
2025-06-18 structured tool output、elicitation、resource links
2025-11-25 URL mode elicitation、sampling 可帶工具、Client ID Metadata Documents、實驗性 tasks
2026-07-28 無狀態化、移除 initialize 握手與 session、server/discover、MRTR、tasks 移出核心

2026-07-28 改的是底層假設,值得拆開看:

  • 無狀態:移除 initialize 握手與 Mcp-Session-Id,每個請求自己帶協定版本與 client 能力。需要跨呼叫狀態的 server,改用自己發的 handle,當一般工具參數傳。
  • server/discover:server 必須實作,用來宣告支援的版本、能力與身分。
  • MRTR(多輪往返請求):以前 server 可以中途反過來向 client 要 roots、sampling 或 elicitation,現在改成 server 回傳「需要更多輸入」的結果,client 帶著答案重試原請求。
  • tasks 變成官方 extension:長時間任務以 tasks/get 輪詢取代會阻塞的 tasks/result,另加 tasks/update 讓 client 補輸入。規格同時新增 extensions 欄位,extension 預設關閉,要明確 opt-in。
  • 快取提示:tools/list 等結果要帶 ttlMs 與 cacheScope,server 也應以固定順序回傳工具,利於 client 快取與 prompt cache 命中。

同一版的棄用清單,寫 server 的人值得逐行讀:

棄用項目 官方遷移方向
Sampling 直接串接 LLM 供應商 API
Roots 用工具參數、resource URI 或 server 設定傳目錄
Logging stdio 寫 stderr,觀測改用 OpenTelemetry
Dynamic Client Registration Client ID Metadata Documents

這四項的最早移除時間,是 2027-07-28 當天或之後發布的第一個版本。棄用不等於移除,官方的說法是它仍是規格的一部分,但新實作不該採用,既有實作應該遷移。HTTP+SSE 傳輸也在棄用表裡,最早可移除的時間是相關提案定案後三個月,實際何時移除由核心維護者在發版時決定。所以新寫的 server,不要再依賴 sampling。

Claude Code 這一側,2.1.232 起有 v2 MCP client,2.1.274 的 changelog 寫明部分安裝預設改用它並協商 2026-07-28(針對直連的 HTTP server),也可用環境變數退回舊行為。stdio server 要更新的版本,文件另有說明,且還在逐步推出,不要假設自己的 stdio server 已經走新協定。從 2.1.265 起,--transport http 遇到舊式 HTTP+SSE server 會自動退回 SSE。治理上,MCP 在 2025-12-09 成為 Linux Foundation 旗下 Agentic AI Foundation 的創始專案。

2026-07-28 版的主要改動與棄用項目

怎麼接

傳輸類型有三種。HTTP 是遠端 server 的建議選項,SSE 文件標為棄用但仍可用,stdio 用 -- 把 Claude 自己的旗標與 server 指令隔開。WebSocket 只能寫進 JSON 設定。

# 遠端 server,走 HTTP
claude mcp add --transport http sentry https://mcp.sentry.dev/mcp

# 本機 stdio server,-- 之後原封不動交給 server
claude mcp add --scope project wordcount -- python3 /絕對路徑/server.py

claude mcp list          # 全部 server 與連線狀態
claude mcp get wordcount # 單一 server 詳情

範圍有三種,存放位置與共享方式不同:

範圍 載入範圍 團隊共享 存放位置
Local(預設) 當前專案 否 ~/.claude.json
Project 當前專案 是 專案根目錄 .mcp.json
User 所有專案 否 ~/.claude.json

同一個 server 重複定義時的優先序,是 Local、Project、User、Plugin 提供、claude.ai connector,企業的 managed 設定排在全部之上。官方文件的說法是:使用最高優先序來源的定義,整筆 server 設定取代,欄位不會跨範圍合併。重複的判斷方式是三種範圍依名稱比對,plugin 與 connector 依 endpoint 比對。

.mcp.json 支援環境變數展開,語法是 ${VAR} 與 ${VAR:-預設值},可用在 command、args、env、url、headers。這樣憑證不用寫進要提交的檔案:

{
  "mcpServers": {
    "internal-api": {
      "type": "http",
      "url": "${API_BASE_URL:-https://api.example.com}/mcp",
      "headers": { "Authorization": "Bearer ${INTERNAL_API_TOKEN}" }
    }
  }
}

這份範例是依文件語法寫的示意,沒有實跑。文件另外規定,遠端 server 的 url 與 headers 裡,有一組固定名單的變數一律讀成空字串,連 :- 預設值也不生效,名單包含 ANTHROPIC_API_KEY、NPM_TOKEN、HTTPS_PROXY 這類。名單外的名稱,例如上面範例的 INTERNAL_API_TOKEN,會正常展開。

同名 server 的優先序與核准閘門

專案 server 的核准閘門(實跑)

.mcp.json 會跟著 repo 走,所以 Claude Code 對專案範圍的 server 有核准機制。官方文件的說法是互動式 session 在使用前會先詢問核准,要重設選擇用 claude mcp reset-project-choices。三個設定鍵:enableAllProjectMcpServers、enabledMcpjsonServers、disabledMcpjsonServers,拒絕優先於前兩者。

實跑結果:

  • 用 claude mcp add --scope project 加完 server,claude mcp list 與 get 都顯示 ⏸ Pending approval (run claude to approve)。
  • 在 .claude/settings.local.json 同時列進 enabledMcpjsonServers 與 disabledMcpjsonServers,狀態變成 ✘ Rejected (see disabledMcpjsonServers in settings),拒絕確實優先。
  • 只列 enabledMcpjsonServers 時,claude mcp get 仍顯示 Pending。文件說明 list 與 get 的專案核准判斷需要先信任該資料夾,我沒有進一步拆開驗證。
  • 用 claude -p(無頭模式)請 haiku 呼叫這個 server 的工具:設定檔裡只有 permissions.allow 的規則、沒有任何核准鍵時,回傳 4;只有 enabledMcpjsonServers、沒有 allow 規則時,也回傳 4。前者說明專案 server 不經核准就被載入,後者說明這個唯讀工具在無頭模式下沒被權限擋下,我沒有進一步查原因。文件對前者的說法是無頭模式無法顯示核准提示。每組只跑一次。

無頭模式不問就載入這件事,對 CI 很重要:在 CI 裡跑 Claude Code,等於預設信任 repo 裡的 .mcp.json。要擋可以用 disabledMcpjsonServers、--setting-sources 或 --strict-mcp-config。另外要分清楚:從 2.1.196 起,未信任的資料夾裡,提交進 repo 的 settings 無法替自己核准 server,但 changelog 寫的範圍是 claude mcp list 與 get 不再啟動這類 server,也就是狀態顯示與互動核准,不會讓 -p 多一層攔截。

驗證

遠端 server 走 OAuth:加好 server 後在 Claude Code 內用 /mcp 登入,token 由 Claude Code 保存並自動更新。也可以用 claude mcp login <name>。如果 server 不支援動態 client 註冊,錯誤訊息會要求預先設定憑證,用 --client-id 與 --client-secret。文件也寫明支援改用 Client ID Metadata Document 的 server,並會自動探索。這正好對上前面棄用清單裡 DCR 的遷移方向。

權限與信任

MCP 工具的名稱格式是 mcp__<server>__<tool>,權限規則依此寫:

規則 效果
mcp__github 或 mcp__github__* 該 server 全部工具
mcp__github__search_issues 單一工具
deny 的 mcp__* 全部 MCP 工具

allow 的萬用字元只能放在字面的 mcp__<server>__ 前綴之後,沒有錨定的 mcp__* 寫在 allow 會被略過並警告,不會自動核准任何東西。另外,帶括號的 mcp__ 規則在載入設定時會被略過,所以寫在 settings 檔的規則沒辦法依參數比對。要依參數擋,得在啟動時用 --disallowedTools 傳 deny 規則。

server 端也能主動要求把關:在 tools/list 的 _meta 設 anthropic/requiresUserInteraction 為 true,每次呼叫都會跳提示,連 bypassPermissions 也一樣,allow 規則無效,文件在同一節標示 2.1.214,另外在 dontAsk 模式下這類呼叫會直接被拒絕。組織層級則有 managed-mcp.json 獨占控制、managedMcpServers、allowedMcpServers 與 deniedMcpServers,denylist 優先於 allowlist。

信任是整件事最重的部分。Claude Code 文件寫的是「Verify you trust each server before connecting it」,安全頁則說 Anthropic 審查 connector 的上架條件,但「does not security-audit or manage any MCP server」。安全頁還有一句容易漏掉:看 .mcp.json 看不出一個 session 能載入的全部 server,plugin、其他範圍與 claude.ai connector 也會帶 server 進來。實跑時 claude mcp list 列出的,除了專案那一個,還有 plugin、使用者範圍與 claude.ai connector 帶來的好幾個。

協定本身的安全要求有兩條值得記住。第一,工具呼叫應該有人在迴路中,規格寫的是 SHOULD 有能拒絕的人;第二,client 必須把 tool annotations 視為不可信,除非來自可信 server。我的範例 server 標了 readOnlyHint,但 client 不該因此就放行,那個標記是 server 自己說的。MCP 的 Security Best Practices 頁也點名 token passthrough 是反模式,server 禁止接受不是發給自己的 token,另外本機 server 若被入侵,攻擊者能以 client 的權限執行任意指令。

關於 tool poisoning,把惡意指令藏在工具描述裡,只有模型看得到,我沒有查到 Anthropic 的專門文章,定義來自第三方 Invariant Labs 的部落格,所以只當成風險類型,不當成官方結論。

用好:context、輸出與工具設計

先把「通則」和「Claude Code 現況」分開。Anthropic 2025-11 的工程文章指出多數 client 把所有工具定義預載進 context,並舉了一個範例:改成讓 agent 以程式碼探索工具檔案,只讀需要的定義,用量從 150,000 tokens 降到 2,000,節省 98.7%。這是文中單一情境的範例,不是通則,而且同一篇也承認執行 agent 產生的程式碼需要沙箱,增加維運與安全成本。

Claude Code 現行預設已經延後載入:官方文件寫的是開場只載入工具名稱與 server instructions,所以多接幾個 server 影響很小,官方沒有給省多少的百分比,社群流傳的數字我不採用。調整方式:

設定 效果
ENABLE_TOOL_SEARCH 未設定 全部延後
auto 或 auto:N 定義總量低於 context 的 10%(或 N%)就全載入
false 全部預載
server 設 "alwaysLoad": true 該 server 的工具啟動即載入

每個工具描述與每個 server 的 instructions 預設截斷在 2,048 字元,2.1.280 起可用 CLAUDE_CODE_MAX_MCP_DESCRIPTION_LENGTH 調整,官方建議關鍵資訊放前面。這跟 Day 19 講的 skill 描述是同一個道理,名單裡的文字每輪都在付成本。

輸出也有上限:超過 10,000 tokens 會警告,預設上限 25,000,可用 MAX_MCP_OUTPUT_TOKENS 調,超過的結果會存成檔案,對話裡改放路徑。server 端可以用 anthropic/maxResultSizeChars 個別放寬,上限 500,000 字元。逾時方面,啟動預設 30 秒(MCP_TIMEOUT),主對話裡的 MCP 呼叫超過兩分鐘會自動轉成背景任務(2.1.212 起)。

預先載入與延後載入的 context 差異

工具設計方面,Anthropic 2025-09 的文章給了幾條,都是官方明載:工具要少而精,重疊的工具會分散 agent 的策略;功能相近的操作整合成一個工具;用共同前綴做命名空間;回傳只給高訊號資訊,別塞 uuid 這類低階識別碼;提供分頁、篩選與截斷,並給合理預設;錯誤訊息要讓 agent 知道下一步怎麼修,而不是只丟錯誤碼。這些原則我認為值得直接當成寫 server 的檢查清單。

MCP 不只有工具

Claude Code 對其他能力的呈現:prompts 變成斜線指令,格式是 /mcp__server__prompt,參數用空白分隔;resources 用 @server:protocol://path 引用;elicitation 不用設定,server 要求時會自動跳出對話框,有表單與開網址兩種模式;server 發出 list_changed 時,互動模式會重新抓取清單。Channels 讓 server 把訊息推進 session,但官方標示還是 research preview,也要用啟動旗標明確指定,不要當成穩定功能。

範圍化:把 MCP 關進 subagent

Day 18 提過 subagent 有 mcpServers 欄位,今天補上用法。官方文件的建議是:想讓某個 server 完全不出現在主對話、不佔工具描述的 context,就把它內聯定義在 subagent 裡,而不是放進 .mcp.json。內聯的 server 在 subagent 啟動時連線、結束時斷線;用字串引用既有 server 則共用父 session 的連線。放在專案 .claude/agents/ 的 agent 檔,內聯 server 要等資料夾被信任才會載入,否則會被略過。

---
name: researcher
description: 查閱外部文件並回報重點,只在需要時連線文件 server。
mcpServers:
  - docs-search:
      type: http
      url: https://example.com/mcp
---

這是依文件格式寫的示意,沒有實跑,網址是占位用。兩個限制要知道:plugin 提供的 subagent 會忽略 mcpServers;主 session 的限制,例如 --strict-mcp-config 與組織的 allowlist,同樣適用於內聯 server。

什麼時候不該接

官方自己就建議優先用 CLI:成本頁寫「Prefer CLI tools when available」,理由是 gh、aws 這類工具不增加逐工具的列表,最佳實務頁更直說 CLI 是與外部服務互動「most context-efficient」的方式。延後載入後差距縮小了,但方向沒變。官方也建議用 /mcp 停用不用的 server。

MCP 與 skill 的關係,官方說的是互補而非取代:「MCP connects Claude to external services. Skills extend what Claude knows」,組合起來就是 MCP 提供連線,skill 教模型怎麼用好。我沒有查到任何官方說某個場景該用 skill 取代 MCP,所以不要把這種說法當官方立場。

另一個判準是副作用。會發文、寄信、部署的 server,建議不要交給沒人看著的自動化 session,只在能當場核准的互動環境裡接。權限規則可以收斂,但發出去的東西收不回來,這是 Day 17 講的事前攔截要處理的那一類。

帶走的檢查清單

  1. 寫 server 的人先看 2026-07-28 的棄用表,新寫的不要依賴 sampling、roots、logging 與 DCR。
  2. .mcp.json 裡的憑證一律用 ${VAR},不要寫死。
  3. 在 CI 或無頭模式跑 Claude Code 前,確認 .mcp.json 是你信任的,必要時用 --strict-mcp-config。
  4. 定期用 claude mcp list 看實際載入了哪些 server,別只看 .mcp.json。
  5. 權限規則寫到 server 或工具層級;settings 檔裡的 MCP 規則不能帶參數,要依參數擋得用 --disallowedTools。
  6. 保持預設的延後載入,只對真的每次都用的 server 設 alwaysLoad;工具描述把關鍵資訊放前面。
  7. 能用 CLI 做的事先用 CLI,用不到的 server 直接停用。

工具能力放得越開,越需要先決定誰有資格接、誰能核准、出事時誰能擋。MCP 這半年的變動多半在協定細節,但那條信任邊界,還是得靠自己寫下來。


上一篇
Day 19:Skill 怎麼寫才會被正確觸發,以及怎麼知道它真的有用
下一篇
Day 21:Plugin 把前四天的東西包成一個單位,怎麼做、怎麼裝、怎麼給團隊,以及它在跨廠標準裡的位置
系列文
資深工程師的 Claude Code 工作筆記 共 23 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言